import com.google.common.base.Strings;
import org.bouncycastle.openssl.PEMWriter;

import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class Tools {

    /**
     *
     * @param a : byte array
     * @param b : byte array
     * @return {a, b}
     */
    public static byte[] concatenateTwoByteArray(byte[] a, byte[] b){
        byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }

    /**
     * convert a written string like a hex format into a byte array
     * @param s : string in hex format, example: EF "3401"
     * @return byte array, example: {(byte)0x34, (byte)0x01}
     */
    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
    /**
     *
     * @param bytes : byte array
     * @return  convert to string in hex format
     */
    public static String fromByteArrayToHexString(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    /**
     *
     * @param bytes : written apdu like a byte array
    * @return apdu like a hex format string
     */
    public static String fromBytesToString(byte[] bytes) {
//    String cadena = "";
//    for (int i = 0; i < apdu.length; i++) {
//    int b = apdu[i] & 0xFF;
//    String auxa = Integer.toHexString(b).toUpperCase();
//    if (auxa.length() == 1) {
//    cadena = cadena + "0" + auxa;
//} else {
//    cadena = cadena + auxa;
//}
//}
//    return cadena;
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);

}

    public static X509Certificate fromByteArrayToX509Certificate(byte[] register) throws CertificateException {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(register);
//        X509Certificate x509Certificate = (X509Certificate)certFactory.generateCertificate(in);
//        return x509Certificate;
        return (X509Certificate)certFactory.generateCertificate(in);
    }

    /**
     *
     * @param cert: flujo de entrada que apunta a un arhivo .cer en disco duro
     * @return el certificado en memoria en el tipo X509Certificate
     */
    public static X509Certificate getCertificate(InputStream cert) {
        X509Certificate tlCert = null;
        CertificateFactory factory;
        try {
            factory = CertificateFactory.getInstance("X509");
        } catch (CertificateException e) {
            System.out.println("Certificado X509 no soportado" + e.getLocalizedMessage());
            return null;
        }

        try {
            tlCert = (X509Certificate) factory.generateCertificate(cert);
        } catch (CertificateException e) {
            System.out.println("Loading certificate exception" + e.getLocalizedMessage());
        }
        return tlCert;
    }

    public static boolean  printPemFormat(Object o, String pathFile) throws IOException {
        PEMWriter pemWriter = new PEMWriter(new PrintWriter(pathFile));
        pemWriter.writeObject(o);
        pemWriter.flush();
        return true;
    }

    /**
     *
     * @param o is an object such as certificate or public key
     * @throws IOException
     * print the object file through System.out
     */
    public static void printPEMFormat(Object o) throws IOException{
        PEMWriter pemWriter = new PEMWriter(new PrintWriter(System.out));
        System.out.println(Strings.repeat("=", 80));
        System.out.println("PEM format");
        System.out.println(Strings.repeat("=", 80));
        System.out.println();
        pemWriter.writeObject(o);
        pemWriter.flush();
        System.out.println();
    }

    public static void printBinFormat(byte[] certRegister, String catcher){
        try  {
            FileOutputStream fos = new FileOutputStream(catcher);
            fos.write(certRegister);
        } catch(Exception e)
        {
            System.out.println("E10 - No se pudo escribir el archivo");
        }
    }

    public static byte[] calculateHash(String alg, String msg) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchProviderException
    {
        alg = alg.substring(0, 3) + "-" + alg.substring(3, alg.length());
        MessageDigest md = MessageDigest.getInstance(alg, "BC");//"SHA-256");
        md.update(msg.getBytes("UTF-8")); // Change this to "UTF-16" if needed
        byte[] digest = md.digest();
        System.out.println("message : " + msg);
        System.out.println("digest  : " + digest.length + " - " + fromBytesToString(digest));
        return digest;
    }
}
